#!/usr/bin/python
# -*- coding: utf-8 -*-

from  reportlab.lib.styles import ParagraphStyle as PS
from  reportlab.platypus import PageBreak, Image, Table, TableStyle, Spacer
from  reportlab.platypus.paragraph import Paragraph
from  reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
from  reportlab.platypus.tableofcontents import TableOfContents
from  reportlab.platypus.frames import Frame
from  reportlab.lib.units import cm
from  reportlab.lib.enums import TA_JUSTIFY
from  reportlab.lib import colors

from  reportlab.pdfgen import canvas
from  reportlab.graphics.shapes import Drawing

from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.graphics.charts.piecharts import Pie
from reportlab.graphics.charts.legends import Legend

from  lpd_commons import *


def lineGraph(data=[(13, 5, 20, 22, 37, 45, 19, 4)]):

    drawing = Drawing(500, 200)
    bc = HorizontalLineChart()
    bc.x = 50
    bc.y = 50
    bc.height = 125
    bc.width = 300
    bc.data = data

    bc.strokeColor = colors.black

    bc.valueAxis.valueMin = 0
    bc.valueAxis.valueMax = 60
    bc.valueAxis.valueStep = 15

    bc.categoryAxis.labels.boxAnchor = 'ne'
    bc.categoryAxis.labels.dx = 8
    bc.categoryAxis.labels.dy = -2
    bc.categoryAxis.labels.angle = 30

    #catNames = string.split('Jan Feb Mar Apr May Jun Jul Aug', ' ')
    catNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug']
    catNames = map(lambda n:n+'-99', catNames)
    bc.categoryAxis.categoryNames = catNames
    drawing.add(bc)
    return drawing

def pieChart(labels, data):

    Label = []
    Data = []
    for j in range(len(data)):
        Data.append(int(str(data[j][0])))
        Label.append(str(labels[j][0]))
    d                       = Drawing(500, 200)
    pc                      = Pie()
    pc.x                    = 100
    pc.y                    = 0
    pc.direction            = 'clockwise'
    pc.width                = 300 
    pc.startAngle           = 270
    pc.data                 = Data
    pc.labels               = Label
    pc.slices.strokeWidth   = 0.2
    #pc.slices[Data.index(min(Data))].popout     = 15
    d.add(pc)
    return d

class report():
    
    story = []
    toc = TableOfContents()

class Estilo():

    centrado = PS(name = 'centrado',
        fontSize = 30,
        leading = 30,
        alignment = 1,
        spaceAfter = 20)

    titulo = PS(name = 'titulo',
        fontSize = 18,
        leading = 18,
        alignment = 1,
        spaceAfter = 20,
        spaceBefore = 180)

    subtitulo = PS(name = 'subtitulo',
        fontSize = 16,
        leading = 18,
        alignment = 1,
        spaceAfter = 180,
        spaceBefore = 1)

    left = PS(name = 'left',
        fontSize = 16,
        leading = 16,
        alignment = 0,
        spaceAfter = 20)

    h1 = PS(
        name = 'Heading1',
        fontSize = 14,
        leading = 16,
        spaceBefore = 150,
        spaceAfter = 60)


    h2 = PS(name = 'Heading2',
        fontSize = 12,
        leading = 14,
        spaceAfter = 10)

    corpo = PS( name = 'corpo',
        fontSize = 11,
        leading = 15,
        spaceAfter = 10,
        alignment = TA_JUSTIFY)

    Autor = PS( name = 'autor',
        fontSize = 12,
        leading = 18,
        alignment = 1)

    logo = PS( name = 'logo',
        fontSize = 16,
        leading = 20,
        alignment = 1)

    local = PS( name = 'local',
        fontSize = 16,
        leading = 20,
        alignment = 1,  
        spaceBefore = 100)

    logo2 = PS( name = 'logo',
        fontSize = 14,
        leading = 20,
        alignment = 1)
    

def Capa():

    # Create an instance of TableOfContents. Override the level styles (optional)
    # and add the object to the story


    report.toc.levelStyles = [
        PS(fontSize=13, name='TOCHeading1', leftIndent=20, firstLineIndent=-20, spaceBefore=10, leading=16),
        PS(fontSize=11, name='TOCHeading2', leftIndent=40, firstLineIndent=-20, spaceBefore=5, leading=12),
        ]

    # Logotipos

    logo = "images/LOGO_IPB.png"
    ipbeja = Image(logo, 3.5*cm, 2.55*cm)
    ipbeja.hAlign='LEFT'
    logo = "images/LOGO_ESTIG.png"
    estig = Image(logo, 3.5*cm, 2.70*cm)
    estig.hAlign='RIGHT'
    tit = [Paragraph("INSTITUTO POLITÉCNICO DE BEJA", Estilo.logo),Paragraph("Escola Superior de Tecnologia e Gestão", Estilo.logo2)]
    data = [[ipbeja, tit, estig]]
    table = Table(data, colWidths=[4*cm, 10*cm, 4*cm])
    table.setStyle([("VALIGN", (0,0), (0,0), "TOP")])

    # Build story.

    report.story.append(table)
    report.story.append(Paragraph('          Mestrado de Engenharia em Segurança Informática', Estilo.logo2))
    report.story.append(Paragraph('<b>Relatório de dados da Firewall</b>', Estilo.titulo))
    pass
 
def Toc():

    report.story.append(Paragraph('<b>Conteúdo</b>', Estilo.left))
    report.story.append(report.toc)
    report.story.append(PageBreak())
    pass

def Titulo(x):

    report.story.append(Paragraph(x, Estilo.subtitulo))
    pass

def Autor(autor):
    for x in autor:
        report.story.append(Paragraph(x, Estilo.Autor))
    #report.story.append(Paragraph('Paulo Jorge Viegas (12834)', Estilo.Autor))
    pass

def CapaBottom(x):
    report.story.append(Paragraph('BEJA', Estilo.local))
    report.story.append(Paragraph(x, Estilo.logo2))
    report.story.append(PageBreak())
    pass

class MyDocTemplate(BaseDocTemplate):
     def __init__(self, filename, **kw):
         self.allowSplitting = 0
         apply(BaseDocTemplate.__init__, (self, filename), kw)
         template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 17*cm, 26*cm, id='F1')])
         self.addPageTemplates(template)

# Entries to the table of contents can be done either manually by
# calling the addEntry method on the TableOfContents object or automatically
# by sending a 'TOCEntry' notification in the afterFlowable method of
# the DocTemplate you are using. The data to be passed to notify is a list
# of three or four items countaining a level number, the entry text, the page
# number and an optional destination key which the entry should point to.
# This list will usually be created in a document template's method like
# afterFlowable(), making notification calls using the notify() method
# with appropriate data.

     def afterFlowable(self, flowable):
         "Registers TOC entries."
         if flowable.__class__.__name__ == 'Paragraph':
             text = flowable.getPlainText()
             style = flowable.style.name
             if style == 'Heading1':
                 self.notify('TOCEntry', (0, text, self.page))
             if style == 'Heading2':
                 self.notify('TOCEntry', (1, text, self.page))


    
def CreatePdf():

    print "Criando o relatório"
    import datetime
    now = datetime.datetime.now()
    Capa()
    if vars.logfile != None:
        Titulo(vars.logfile)
    else:
        Titulo("De {0} a {1}".format(vars.li[0][0],vars.li[len(vars.li)-1][0]))
    Autor(["Luís Filipe Reis (12829)",'Paulo Jorge Viegas (12834)'])
    mes=["","Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"]
    #print int(now.strftime("%d")), int(now.strftime("%m")), mes[int(now.strftime("%m"))]
    CapaBottom("{0} de {1} de {2}".format(int(now.strftime("%d")),mes[int(now.strftime("%m"))],now.strftime("%Y")))
    Toc()

    report.story.append(Paragraph('Pontos de Acesso', Estilo.h1))
    #report.story.append(Paragraph('Resumo', Estilo.h2))
    if vars.log:
        report.story.append(Paragraph('Com base no ficheiro de log da <i>Firewall</i> do cliente processamos as tentativas de acesso do exterior para dentro da rede do cliente, tendo-se descoberto {0} tentativas de acesso a partir de {1} pontos de acesso diferentes.'.format(len(vars.li), len(vars.iplist)), Estilo.corpo))
        if (vars.lines - len(vars.li)) != 0:
            report.story.append(Paragraph("Durante o processamento foram encontrados {0} erros no ficheiro de log. Estes erro foram guardados no ficheiro <i>log_error</i> para analise posterior. Na sua visualização deverá de ser possivel encontrar IP's com origem na rede interna, IP' vazios e IP's de IPv6 que não se encontram ainda identificados na base de dados da Google".format(vars.lines - len(vars.li)), Estilo.corpo))
        if (vars.data_error) != 0:
            report.story.append(Paragraph('Durante o processamento foram encontrados {0} erros no gravação de registos na Base de Dados. Estes erro foram guardados no ficheiro <i>data_error</i> para analise posterior.'.format(vars.data_error), Estilo.corpo))

        if vars.sql:
            report.story.append(Paragraph('Os dados processsados foram guardados encriptados numa base de dados de formato <i>SQLite3</i>: <b>myufwdata.db</b>.', Estilo.corpo))

    else:
        report.story.append(Paragraph('Com base no ficheiro de SQL com os dados do log da <i>Firewall</i> do cliente processamos as tentativas de acesso do exterior para dentro da rede do cliente, tendo-se descoberto {0} tentativas de acesso a partir de {1} pontos de acesso diferentes.'.format(len(vars.li), len(vars.iplist)), Estilo.corpo))

    report.story.append(Paragraph("Os dados relativos a este relatório estão compreendidos entre as {1} horas do dia {0} e as {3} horas do dia  {2}".format(vars.li[0][0],vars.li[0][1], vars.li[len(vars.li)-1][0], vars.li[len(vars.li)-1][1]), Estilo.corpo))

    if vars.csv:
        report.story.append(Paragraph('Foi gerado um ficheiro em fomato <i>CSV</i>: <b>{1}.csv</b> que contém os dados relativos aos {0} registos processados.'.format(len(vars.li), len(vars.csvfile)), Estilo.corpo))

    report.story.append(Paragraph('Este Capítulo é composto por tabelas com vários dados relativos às tentativas de acesso.', Estilo.corpo))
    report.story.append(PageBreak())


    report.story.append(Paragraph("Tabela de IP's", Estilo.h2))
    from operator import itemgetter
    pontos = []
    #   0      1       2    3      4           5        6          7
    # 'Data', 'Hora', 'IP','País','Time Zone','Cidade','Latitude','Longitude'
    for x in sorted(vars.iplist, key=itemgetter(1,2)):
        pontos.append([
                x,
                [s[3:4] for s in vars.li if x in s][0][0],
                [s[5:6] for s in vars.li if x in s][0][0],
                str(len([s for s in vars.li if x in s]))
                ])
                

    table = Table([["IP", "País", "Cidade", "Quant"]] + sorted(pontos, key=itemgetter(1,2)),colWidths=[6*cm, 4*cm, 4*cm, 1*cm])
    table.setStyle(TableStyle([('LINEABOVE', (0,0), (-1,-1), 1, colors.black)]))
    table.setStyle(TableStyle([('FONT', (0,0), (-1,0), "Helvetica-Bold", 8),
            ("FONT", (0,1), (-1,-1), "Helvetica", 7)]))
    table.setStyle([("VALIGN", (0,0), (0,0), "TOP")])
    report.story.append(table)
    report.story.append(PageBreak())

    paises = []
    tmp = ''
    tmp_count = 0
    n = 0
    for a,x,b,c in sorted(pontos, key=itemgetter(1,2)):
        if tmp == '': tmp = x
        if x == tmp: tmp_count = tmp_count + int(c)
        else:
            n +=1
            paises.append([n, tmp,str(tmp_count),"{0:.2f}".format((tmp_count*100.00)/len(vars.li))])
            tmp = x
            tmp_count = int(c)
    paises.append([(n+1),x,str(tmp_count),str("{0:.2f}".format((tmp_count*100.00)/len(vars.li)))])

    report.story.append(Paragraph('Gráficos', Estilo.h1))
    report.story.append(Paragraph('Acessos por País', Estilo.h2))

    drawing = pieChart([y[0:1] for y in paises], [y[2:3] for y in paises])
    report.story.append(drawing)
    report.story.append(Spacer(0, 2.5*cm))

    table = Table([["","País", "Quant", "%"]] + sorted(paises, key=itemgetter(0)),colWidths=[1*cm, 6*cm, 1.5*cm, 1.5*cm])
    table.setStyle(TableStyle([('LINEABOVE', (0,0), (-1,-1), 1, colors.black)]))
    table.setStyle(TableStyle([('FONT', (0,0), (-1,0), "Helvetica-Bold", 8),
            ("FONT", (0,1), (-1,-1), "Helvetica", 7)]))
    table.setStyle([("VALIGN", (0,0), (0,0), "TOP")])
    report.story.append(table)
    report.story.append(PageBreak())

    report.story.append(Paragraph('Mapa Geográfico', Estilo.h1))
    mapa = "mapa.png"
    import PIL
    from PIL import Image as _Image
    basewidth = 450
    img = _Image.open(mapa)
    maps = Image(mapa, basewidth, int((float(img.size[1]) * float(basewidth/float(img.size[0])))))
    maps.hAlign='CENTER'
    report.story.append(maps)

    doc = MyDocTemplate('UfwReport.pdf')
    doc.multiBuild(report.story)
